package com.snake

import androidx.compose.runtime.Composable
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.graphics.drawscope.DrawScope

import com.snake.SnakeBody.Type

import kotlin.math.abs

// 蛇
class Snake {
    private var mCauda: SnakeBody   // 蛇尾
    private var mDirection: Int     // 移动方向

    /**
     * 构造方法。
     */
    constructor() {
        // 初始化成员
        mCauda = SnakeBody(Type.SNAKE)
        this.head = mCauda
        mDirection = Const.DIRECTION_DOWN
    }

    /**
     * 画自身。
     * @param drawer    绘图者
     */
    fun draw(drawer: DrawScope) {
        var snakeBody: SnakeBody? = mCauda
        while (snakeBody != null) {
            snakeBody.draw(drawer)
            snakeBody = snakeBody.next
        }
    }

    /**
     * 吃果子，即将果子放到蛇尾。
     * @param apple 果子
     */
    fun eat(apple: SnakeBody) {
        // 设置吃到的果子的位置
        var position = head.position.copy()
        when (mDirection) {
            Const.DIRECTION_DOWN -> position += Offset(0f, 1f)
            Const.DIRECTION_LEFT -> position -= Offset(1f, 0f)
            Const.DIRECTION_RIGHT -> position += Offset(1f, 0f)
            Const.DIRECTION_UP -> position -= Offset(0f, 1f)
            else -> { position }
        }
        apple.position = position

        // 改变果子的类型
        apple.setType(Type.SNAKE)

        // 将吃到的果子变成蛇头
        head.next = apple
        this.head = apple
    }

    /**
     * 获取蛇头。
     * @return 蛇头
     */
    var head: SnakeBody
        private set

    /**
     * 初始化。
     */
    @Composable
    fun Init() {
        mCauda.Init()
    }

    /**
     * 移动。
     * @return 蛇头碰到自身或游戏区域边界则返回 true，否则返回 false
     */
    fun move(): Boolean {
        // 计算蛇尾的新位置并抹除蛇尾
        var point = head.position.copy()
        when (mDirection) {
            Const.DIRECTION_DOWN -> {
                if (point.y + 1 >= Const.GAME_BOARD_GRID_COUNT_V) {
                    // 如果蛇头超出游戏区域下边界，则返回
                    return true
                }
                point += Offset(0f, 1f)
            }
            Const.DIRECTION_LEFT -> {
                if (point.x - 1 < 0) {
                    // 如果蛇头超出游戏区域左边界，则返回
                    return true
                }
                point -= Offset(1f, 0f)
            }
            Const.DIRECTION_RIGHT -> {
                if (point.x + 1 >= Const.GAME_BOARD_GRID_COUNT_H) {
                    // 如果蛇头超出游戏区域右边界，则返回
                    return true
                }
                point += Offset(1f, 0f)
            }
            Const.DIRECTION_UP -> {
                if (point.y - 1 < 0) {
                    return true // 如果蛇头超出游戏区域上边界，则返回
                }
                point -= Offset(0f, 1f)
            }
        }
        mCauda.position = point

        // 将蛇尾的下一个结点设置为蛇尾、原蛇尾设置成蛇头
        head.next = mCauda
        this.head = mCauda
        mCauda = mCauda.next!!
        head.next = null

        // 检查蛇头是否碰到蛇身
        var snakeBody = mCauda
        while (snakeBody != this.head) {
            if (snakeBody.position == head.position) {
                return true
            }
            snakeBody = snakeBody.next!!
        }

        return false
    }

    /**
     * 检查某点是否与蛇身位置重叠。
     * @param point 要检查的点
     * @return 点与蛇身位置重叠则返回 true，否则返回 false
     */
    fun pointIsOnMe(point: Offset): Boolean {
        var snakeBody: SnakeBody? = mCauda
        while (snakeBody != null) {
            if (snakeBody.position == point) {
                return true
            }
            snakeBody = snakeBody.next
        }
        return false
    }

    /**
     * 转弯。
     * @param direction 方向
     */
    fun turn(direction: Int) {
        // 如果方向与当前方向相反(想要直接调头)，则直接返回
        if (abs((direction - mDirection).toDouble()) == 2.0) {
            return
        }

        mDirection = direction
    }
}
